package controllers

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"cvevulner/common"
	"cvevulner/errcode"
	"cvevulner/models"
	"cvevulner/taskhandler"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
)

type CveIssueInfoController struct {
	beego.Controller
}

func (c *CveIssueInfoController) RetData(resp map[string]interface{}) {
	c.Data["json"] = resp
	c.ServeJSON()
}

type CveIssueInfoData struct {
	IssueNum       string  `json:"issue_id"`
	CveNum         string  `json:"CVE_num"`
	OpeneulerScore float64 `json:"openeuler_score"`
	NvdScore       float64 `json:"NVD_score"`
	Branch         string  `json:"milestone"`
}

type CveIssueUpdate struct {
	CveId       string `json:"cve_id"`
	PackageName string `json:"package_name"`
}

const url = "https://gitee.com/%s/%s/issues/%s"

// @Title Get cveissueinfo
// @Description get cve
// @Param	status	int	true (0,1,2)
// @Success 200 {object} CveIssueInfoData
// @Failure 403 :status is err
// @router / [get]
func (u *CveIssueInfoController) Get() {
	req := u.Ctx.Request
	addr := req.RemoteAddr
	logs.Info("Method: ", req.Method, "Client request ip address: ", addr,
		", Header: ", req.Header, ", body: ", req.Body)
	resp := make(map[string]interface{})
	var ird []CveIssueInfoData
	resp["code"] = errcode.RecodeNodata
	resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
	resp["body"] = []CveIssueInfoData{}
	resp["total"] = 0
	//defer u.RetData(resp)
	milestone := u.GetString("milestone", "")
	count := models.QueryIssueCount(milestone)
	if count > 0 {
		resp["total"] = count
		resp["code"] = errcode.RecodeOk
		resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
		currentPage, err := u.GetInt("currentPage", 1)
		if err != nil {
			logs.Error("err: ", err, ", currentPage: ", currentPage)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetData(resp)
			return
		}
		pageSize, err := u.GetInt("pageSize", 100)
		if err != nil {
			logs.Error("err: ", err, ", pageSize: ", pageSize)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetData(resp)
			return
		}
		issueData, issueErr := models.QueryCveIssueByBranch(currentPage, pageSize, milestone)
		if issueErr == nil && len(issueData) > 0 {
			for _, issues := range issueData {
				var irda CveIssueInfoData
				irda.CveNum = issues.CveNum
				irda.IssueNum = issues.IssueNum
				irda.OpeneulerScore = issues.OpeneulerScore
				irda.NvdScore = issues.NvdScore
				irda.Branch = issues.AffectProduct
				ird = append(ird, irda)
			}
			resp["body"] = ird
			resp["code"] = errcode.RecodeOk
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
			u.RetData(resp)
		} else {
			resp["code"] = errcode.RecodeNodata
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
			u.RetData(resp)
			return
		}
	}
}

func (u *CveIssueInfoController) Post() {
	var req []CveIssueUpdate

	err := json.Unmarshal(u.Ctx.Input.RequestBody, &req)
	if err != nil {
		logs.Error("update cve issue score fail, err: ", err)
		return
	}

	if len(req) == 0 {
		return
	}

	logs.Info("updates cve issue :", req)

	for _, c := range req {
		cve := models.VulnCenter{CveNum: c.CveId, RepoName: c.PackageName}
		err = models.GetVulnCenterByCid(&cve, "CveNum", "RepoName")
		if err != nil {
			logs.Error(err)
			continue
		}

		err = taskhandler.UpdateCveIssueScore(cve)
		if err != nil {
			logs.Error("update cve score failed, err:", err)
		}
	}

}

type CveAllIssueController struct {
	beego.Controller
}

func (c *CveAllIssueController) RetCveData(resp map[string]interface{}) {
	c.Data["json"] = resp
	c.ServeJSON()
}

type CveAllIssueoData struct {
	IssueNum            string  `json:"issue_id"`
	CveNum              string  `json:"CVE_num"`
	OpeneulerScore      float64 `json:"openeuler_score"`
	NvdScore            float64 `json:"NVD_score"`
	Branch              string  `json:"milestone"`
	CveLevel            string  `json:"CVE_level"`
	PlanClosedTime      string  `json:"plan_closed_time"`
	CvePublicTime       string  `json:"CVE_public_time"`
	CveVtopicPublicTime string  `json:"CVE_vtopic_public_time"`
	CveVtopicRecTime    string  `json:"CVE_vtopic_rec_time"`
	RpmPublicTime       string  `json:"rpm_public_time"`
	SaPublicTime        string  `json:"SA_public_time"`
	Version             string  `json:"version"`
	Component           string  `json:"component"`
	Create              string  `json:"create_time,omitempty"`
	Url                 string  `json:"issue_url,omitempty"`
	User                string  `json:"user,omitempty"`
}

// @Title Obtain all cve data and provide operation kanban for use
// @Description get issue
// @Param	pageSize 1,currentPage 10, updatetime nil
// @Success 200 {object} CveAllIssueoData
// @Failure 403 :status is err
// @router / [get]
func (u *CveAllIssueController) Get() {
	req := u.Ctx.Request
	addr := req.RemoteAddr
	logs.Info("Method: ", req.Method, "Client request ip address: ", addr,
		", Header: ", req.Header, ", body: ", req.Body)
	resp := make(map[string]interface{})
	var cid []CveAllIssueoData
	resp["code"] = errcode.RecodeNodata
	resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
	resp["body"] = []CveAllIssueoData{}
	resp["total"] = 0
	//defer u.RetCveData(resp)
	communityFlag, flagErr := u.GetInt("communityFlag", 0)
	if flagErr != nil {
		communityFlag = 0
	}
	var cves = make([]string, 0)
	cve := u.GetString("cveNums")
	if len(cve) != 0 {
		cves = strings.Split(cve, ",")
	}
	if len(cves) > 0 {
		u.cveForIssue(cves, communityFlag)
		return
	}
	conditions := u.GetString("conditions", "")
	if len(conditions) != 0 {
		u.cvePackForIssue(conditions, communityFlag)
		return
	}
	startTime := u.GetString("startTime", "")
	count := models.QueryCveAllIssueCount(communityFlag, startTime)
	if count > 0 {
		resp["total"] = count
		resp["code"] = errcode.RecodeOk
		resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
		currentPage, err := u.GetInt("currentPage", 1)
		if err != nil {
			logs.Error("err: ", err, ", currentPage: ", currentPage)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetCveData(resp)
			return
		}
		pageSize, err := u.GetInt("pageSize", 100)
		if err != nil {
			logs.Error("err: ", err, ", pageSize: ", pageSize)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetCveData(resp)
			return
		}
		issueData, issueErr := models.QueryCveAllIssueData(currentPage, pageSize, communityFlag, startTime)
		if issueErr == nil && len(issueData) > 0 {
			for _, issues := range issueData {
				var irda CveAllIssueoData
				irda.CveNum = issues.CveNum
				irda.IssueNum = issues.IssueNum
				irda.Version = issues.OwnedVersion
				irda.Component = issues.OwnedComponent
				irda.OpeneulerScore = issues.OpeneulerScore
				irda.NvdScore = issues.NvdScore
				irda.Branch = issues.AffectedVersion
				irda.CveLevel = issues.CveLevel
				irda.CveVtopicPublicTime = issues.FirstPerTime
				irda.CveVtopicRecTime = issues.FirstGetTime
				irda.Create = issues.CreateTime.Format("2006-01-02 15:04:05")
				irda.Url = fmt.Sprintf(url, issues.Owner, issues.Repo, issues.IssueNum)
				irda.PlanClosedTime = taskhandler.CvePlanCloseTime(issues.CreateTime, issues.CveLevel, false, false)
				irda.CvePublicTime = issues.CpublicTime
				if len(issues.RpmReleaseTime) > 2 {
					irda.RpmPublicTime = issues.RpmReleaseTime
				} else {
					irda.RpmPublicTime = issues.SaReleaseTime
				}
				irda.SaPublicTime = issues.SaReleaseTime
				cid = append(cid, irda)
			}
			resp["body"] = cid
			resp["code"] = errcode.RecodeOk
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
			u.RetCveData(resp)
		} else {
			resp["code"] = errcode.RecodeNodata
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
			u.RetCveData(resp)
			return
		}
	}
}

func (u *CveAllIssueController) cveForIssue(cves []string, communityFlag int) {
	resp := make(map[string]interface{})
	issueData, issueErr := models.QueryCveIssue(cves, communityFlag)
	resp["code"] = errcode.RecodeOk
	resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
	resp["body"] = nil
	if issueErr != nil {
		resp["code"] = errcode.RecodeNodata
		resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
		u.RetCveData(resp)
		return
	}
	var res = make([]CveAllIssueoData, 0, len(issueData))

	for _, issues := range issueData {
		var irda CveAllIssueoData
		irda.CveNum = issues.CveNum
		irda.IssueNum = issues.IssueNum
		irda.Version = issues.OwnedVersion
		irda.Component = issues.OwnedComponent
		irda.Create = issues.CreateTime.Format("2006-01-02 15:04:05")
		irda.Url = fmt.Sprintf(url, issues.Owner, issues.Repo, issues.IssueNum)
		owner, accessToken := common.GetOwnerAndToken("", issues.OrganizateId)
		err, issueBody := taskhandler.GetGiteeIssue(accessToken, owner, issues.Repo, issues.IssueNum)
		if err == nil && issueBody != nil {
			if s, ok := issueBody["created_at"].(string); ok {
				if t, err := time.Parse("2006-01-02T15:04:05+08:00", s); err == nil {
					irda.Create = t.Format("2006-01-02 15:04:05")
				}
			}

			if u, ok := issueBody["user"].(map[string]interface{}); ok {
				if name, ok := u["name"].(string); ok {
					irda.User = name
				}
			}
		}
		res = append(res, irda)
	}
	resp["body"] = res
	u.RetCveData(resp)
}

func (u *CveAllIssueController) cvePackForIssue(conditions string, communityFlag int) {
	resp := make(map[string]interface{})
	var req []models.Cve
	err := json.Unmarshal([]byte(conditions), &req)
	if err != nil {
		resp["code"] = -1
		resp["errmsg"] = err.Error()
		u.RetCveData(resp)
		return
	}
	issueData, issueErr := models.QueryCvePackIssue(req, communityFlag)
	resp["code"] = errcode.RecodeOk
	resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
	resp["body"] = nil
	if issueErr != nil {
		resp["code"] = errcode.RecodeNodata
		resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
		u.RetCveData(resp)
		return
	}
	var res []CveAllIssueoData

	for _, issues := range issueData {
		var irda CveAllIssueoData
		irda.CveNum = issues.CveNum
		irda.IssueNum = issues.IssueNum
		irda.Version = issues.OwnedVersion
		irda.Component = issues.OwnedComponent
		irda.Create = issues.CreateTime.Format("2006-01-02 15:04:05")
		res = append(res, irda)
	}
	resp["body"] = res
	u.RetCveData(resp)
}

type KanbanCveAllIssueController struct {
	beego.Controller
}

func (c *KanbanCveAllIssueController) RetCveData(resp map[string]interface{}) {
	c.Data["json"] = resp
	c.ServeJSON()
}

type KanbanCveAllIssueoData struct {
	IssueNum            string  `json:"issue_id"`
	CveNum              string  `json:"CVE_num"`
	OpeneulerScore      float64 `json:"openeuler_score"`
	NvdScore            float64 `json:"NVD_score"`
	Branch              string  `json:"milestone"`
	CveLevel            string  `json:"CVE_level"`
	PlanClosedTime      string  `json:"plan_closed_time"`
	CvePublicTime       string  `json:"CVE_public_time"`
	CveVtopicPublicTime string  `json:"CVE_vtopic_public_time"`
	CveVtopicRecTime    string  `json:"CVE_vtopic_rec_time"`
	RpmPublicTime       string  `json:"rpm_public_time"`
	SaPublicTime        string  `json:"SA_public_time"`
}

// @Title Obtain all cve data and provide operation kanban for use
// @Description get issue
// @Param	pageSize 1,currentPage 10, updatetime nil
// @Success 200 {object} CveAllIssueoData
// @Failure 403 :status is err
// @router / [get]
func (u *KanbanCveAllIssueController) Get() {
	req := u.Ctx.Request
	addr := req.RemoteAddr
	logs.Info("Method: ", req.Method, "Client request ip address: ", addr,
		", Header: ", req.Header, ", body: ", req.Body)
	resp := make(map[string]interface{})
	var cid []CveAllIssueoData
	resp["code"] = errcode.RecodeNodata
	resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
	resp["body"] = []CveAllIssueoData{}
	resp["total"] = 0
	//defer u.RetCveData(resp)
	communityFlag, flagErr := u.GetInt("communityFlag", 0)
	if flagErr != nil {
		communityFlag = 0
	}
	count := models.QueryCveOrgIssueCount(communityFlag)
	if count > 0 {
		resp["total"] = count
		resp["code"] = errcode.RecodeOk
		resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
		currentPage, err := u.GetInt("currentPage", 1)
		if err != nil {
			logs.Error("err: ", err, ", currentPage: ", currentPage)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetCveData(resp)
			return
		}
		pageSize, err := u.GetInt("pageSize", 100)
		if err != nil {
			logs.Error("err: ", err, ", pageSize: ", pageSize)
			resp["errno"] = errcode.RecodeParamErr
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeParamErr)
			u.RetCveData(resp)
			return
		}
		issueData := models.QueryCveOrgIssueData(currentPage, pageSize, communityFlag)
		if len(issueData) > 0 {
			for _, org := range issueData {
				var irda CveAllIssueoData
				irda.CveNum = org.CveNumber
				irda.IssueNum = org.Number
				issues, isErr := models.QueryCveSingleIssueData(communityFlag, org.RepoPath, org.CveNumber, org.Number)
				if isErr != nil {
					cid = append(cid, irda)
				} else {
					irda.Version = issues.OwnedVersion
					irda.Component = issues.OwnedComponent
					irda.OpeneulerScore = issues.OpeneulerScore
					irda.NvdScore = issues.NvdScore
					irda.Branch = issues.AffectedVersion
					if issues.OpeneulerScore >= 0 {
						irda.CveLevel = models.OpenEulerScoreProc(issues.OpeneulerScore)
					}
					irda.CveVtopicPublicTime = issues.FirstPerTime
					irda.CveVtopicRecTime = issues.FirstGetTime
					irda.PlanClosedTime = taskhandler.CvePlanCloseTime(issues.CreateTime, issues.CveLevel, false, false)
					irda.CvePublicTime = issues.CpublicTime
					if len(issues.RpmReleaseTime) > 2 {
						irda.RpmPublicTime = issues.RpmReleaseTime
					} else {
						irda.RpmPublicTime = issues.SaReleaseTime
					}
					irda.SaPublicTime = issues.SaReleaseTime
					cid = append(cid, irda)
				}
			}
			resp["body"] = cid
			resp["code"] = errcode.RecodeOk
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeOk)
			u.RetCveData(resp)
		} else {
			resp["code"] = errcode.RecodeNodata
			resp["errmsg"] = errcode.RecodeText(errcode.RecodeNodata)
			u.RetCveData(resp)
			return
		}
	}
}
